home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 November / macformat-018.iso / Utility Spectacular / AfterDark / Rae ƒ / rae.c next >
Encoding:
Text File  |  1994-03-06  |  17.3 KB  |  708 lines  |  [TEXT/KAHL]

  1.  
  2.  
  3. // see the README file for version notes
  4.  
  5. #include "GraphicsModule_Types.h"
  6. #include "Sounds.h"
  7.  
  8.  
  9.  
  10. typedef struct sicn {
  11.     unsigned char bits[32];
  12. } sicnStruct, *sicnPtr, **sicnHandle;
  13.  
  14. typedef struct infostruct {
  15.     /*unsigned short*/
  16.     short            GND[128];                        // ??
  17.     BitMap            face;
  18.  
  19.     Handle            faceSICN;                        // faces resource
  20.     short            numFaces;
  21.     short            curFace;
  22.     short            lastFace;
  23.     
  24.     short            failedToStart;                    // watchdog 
  25.     
  26.     short            time;                            // "timer" for decay, etc
  27.     short            state;
  28.     int                x, y,
  29.                     xvel, yvel,
  30.                     xacc, yacc,
  31.                     xpos, ypos;
  32.     int                xx, yy;                            // temp/save values
  33.     Rect            myRect;
  34.     Handle            sndBounce;                        // handle to 'boink' sound
  35.     Handle            sndScream;                        // scream sound
  36.     SoundInfoHandle    soundInfo;                        // handle to AD sound thing
  37.     long            soundTicks;                        // sound timer to keep us from 
  38.                                                     // sounding yucky
  39.     
  40. } infostruct, *infostructPtr, **infostructHandle;
  41.  
  42. #define BOING_SOUND_ID    256
  43. #define SCREAM_SOUND_ID 129
  44.  
  45. #define BASE_FACE_ID    256                        // MENUs items are 1-based, not 0
  46.  
  47. #define DOUBLE_FACE
  48.  
  49. #define SOUND_TIMER        3                        // wait for # ticks
  50.                                                 // before playing the next one
  51. #define MAX_ITERATIONS    (128)
  52.  
  53. unsigned short RangedRdm( unsigned short min, unsigned short max );
  54. void SetInhibited(infostructPtr info, int Usage);
  55.  
  56. int drawit(GMParamBlockPtr params, infostructPtr info, int x, int y );
  57. int decay(int v);
  58.  
  59. #if 1
  60. #define XMIN    (params->qdGlobalsCopy->qdThePort->portRect.left)
  61. #define YMIN    (params->qdGlobalsCopy->qdThePort->portRect.top)
  62. #define XMAX    (params->qdGlobalsCopy->qdThePort->portRect.right)
  63. #define YMAX    (params->qdGlobalsCopy->qdThePort->portRect.bottom)
  64. #define TOP        YMIN
  65. #define BOT        (YMAX-1)
  66. #else
  67. #define HEIGHT  16
  68. #define WIDTH   16
  69. #define XMIN    0
  70. #define YMIN    0
  71. #define XMAX    511
  72. #define YMAX    341
  73. #define TOP     YMIN
  74. #define BOT     (YMAX-1)
  75. #endif
  76.  
  77. enum {
  78.     RAE_STARTING,
  79.     RAE_FALLING,
  80.     RAE_SETTLING,
  81.     RAE_DONE,
  82.     RAE_RESET
  83. };
  84.  
  85.  
  86. // these are the functs that need defined ...
  87. OSErr DoInitialize(Handle *storage, RgnHandle blankRgn, GMParamBlockPtr params);
  88. OSErr DoClose(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params);
  89. OSErr DoBlank(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params);
  90. OSErr DoDrawFrame(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params);
  91. OSErr DoSetUp(RgnHandle blankRgn, short message, GMParamBlockPtr params);
  92.  
  93. // extra ones
  94. OSErr DoSelected(RgnHandle blankRgn, short message, GMParamBlockPtr params);
  95. OSErr DoAboutBox(RgnHandle blankRgn, short message, GMParamBlockPtr params);
  96.  
  97.  
  98. // this is borrowed from the example code from Bouncing Ball ...
  99. /* some macros to simplify synchronizing to the vertical retrace. */
  100. #define SynchFlag(m) (params->monitors->monitorList[m].synchFlag)
  101. #define SynchVBL(m) synchFlag = &SynchFlag(m); *synchFlag = false; while(!*synchFlag);
  102.  
  103.  
  104. static unsigned char facebits[32] = {
  105.     0x07, 0xe0, 0x18, 0x18, 0x20, 0x04, 0x42, 0x42, 0x42, 0x42,
  106.     0x82, 0x41, 0x80, 0x01, 0x80, 0x01, 0x84, 0x21, 0x88, 0x11,
  107.     0x94, 0x29, 0x43, 0xc2, 0x40, 0x02, 0x20, 0x04, 0x18, 0x18,
  108.     0x07, 0xe0
  109. };
  110.  
  111. //////////////////////////////////////////////////////////////////////////////////////
  112. // this is the first funct called by AD ... we need to allocate and initialize here
  113. OSErr
  114. DoInitialize(Handle *storage, RgnHandle blankRgn, GMParamBlockPtr params) {
  115.     Handle             h;
  116.     infostructPtr    info;
  117.     short            offRowBytes;
  118.     // error messages
  119.     StringPtr spaceErrMsg = (StringPtr)"\prae: Not enough memory!!";
  120.     // misc vars  ..
  121.     short            i; 
  122.  
  123.     // Randomize...
  124.     params->qdGlobalsCopy->qdRandSeed = TickCount();
  125.  
  126.     h = NewHandle( sizeof(infostruct) );
  127.     if (h == (Handle)nil) {
  128.         BlockMove(spaceErrMsg, params->errorMessage, spaceErrMsg[0]+1);
  129.         return ModuleError;
  130.     }
  131.     *storage = h;
  132.     MoveHHi(h);
  133.     HLock(h);
  134.     info = (infostructPtr)(*h);
  135.  
  136.     info->myRect = params->qdGlobalsCopy->qdThePort->portRect;
  137. //    SetRect( &(info->myRect), 0, 0, XMAX+1, YMAX+1);
  138.     
  139. // sound?
  140.     if (params->systemConfig & SoundAvailable)  {
  141.         info->sndBounce = GetResource('snd ', BOING_SOUND_ID + params->controlValues[1]);
  142.         info->sndScream = GetResource('snd ', SCREAM_SOUND_ID);
  143.     }
  144.     
  145.     if (info->sndBounce != (Handle)NULL || info->sndScream != (Handle)NULL ) 
  146.         info->soundInfo = OpenSound(params);
  147.     else info->soundInfo = NULL;
  148.  
  149.     info->soundTicks = TickCount();
  150.  
  151.     info->faceSICN = GetResource('SICN', BASE_FACE_ID + params->controlValues[1]);
  152.     MoveHHi( info->faceSICN );
  153.     
  154.     if (info->faceSICN != (Handle)NULL) {
  155.         info->numFaces = SizeResource( info->faceSICN ) / sizeof(sicnStruct) ;
  156.         info->face.baseAddr = *info->faceSICN;
  157.         info->face.rowBytes = 2;
  158.         SetRect( &(info->face.bounds), 0, 0, 16, 16);
  159.         info->curFace = info->lastFace = 0;
  160.         
  161.     } else { // fall back to the default, hard-coded facebits
  162.         SysBeep(0);
  163.         // set up the bitmap
  164.         info->face.baseAddr = (QDPtr) &facebits[0];
  165.         info->face.rowBytes = 2;
  166.         SetRect( &(info->face.bounds), 0, 0, 16, 16);
  167.     }
  168.  
  169. // set up the GND 
  170.     for (i=0; i<128; i++) {
  171.         info->x = i<<3;
  172.         if (info->x <= XMIN+8 || info->x >= XMAX-8)
  173.             info->GND[i] = 0;
  174.         else {
  175.             info->GND[i] = BOT - 9;
  176.             if (i&01)
  177.                 if (info->GND[i-1]==0)
  178.                     info->GND[i] = 0;
  179.                 else
  180.                     info->GND[i] -= 7;
  181.         }
  182.     }
  183.  
  184.     info->state = RAE_STARTING;
  185.     info->failedToStart = 0;
  186.     
  187.     HUnlock( h);
  188.     return noErr;
  189. }
  190.  
  191. //////////////////////////////////////////////////////////////////////////////////////
  192. // the screen saver has been awakened! time to ditch the storage and wave goodbye
  193. OSErr 
  194. DoClose(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params) {
  195.  
  196.     // soundInfoHandle to ditch ??
  197.     if ( ( (infostructPtr)(*storage) )->soundInfo  != NULL)
  198.         CloseSound( ((infostructPtr)(*storage) )->soundInfo, 
  199.                 params->sndChannel);
  200.     
  201.     // ditch the bounce sound
  202.     if (((infostructPtr)(*storage) )->sndBounce != (Handle)NULL)
  203.         ReleaseResource( ((infostructPtr)(*storage) )->sndBounce );
  204.         
  205.     // ditch the scream sound also
  206.     if (  ((infostructPtr)(*storage) )->sndScream  != (Handle)NULL)
  207.         ReleaseResource( ((infostructPtr)(*storage) )->sndScream);
  208.  
  209.     // ditch the SICN handle
  210.     if ( ((infostructPtr)(*storage) )->faceSICN != (Handle)NULL)
  211.         ReleaseResource( ((infostructPtr)(*storage) )->faceSICN );
  212.  
  213.     // finally, ditch the memory we had allocated
  214.     DisposHandle( storage);
  215.     return noErr;
  216. }
  217.  
  218.  
  219.  
  220. //////////////////////////////////////////////////////////////////////////////////////
  221. // make the screen go black
  222. OSErr
  223. DoBlank(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params) {
  224.     infostructPtr        info;
  225.     
  226. #if 0    // not used
  227.     HLock(storage);
  228.     info = (infostructPtr)(*storage);
  229. #endif
  230.     
  231.     // darken the screen ...
  232.     FillRgn(blankRgn, params->qdGlobalsCopy->qdBlack);
  233.  
  234. #if 0    // not used
  235.     HUnlock( storage);
  236. #endif
  237.     
  238.     return noErr;
  239.  
  240. }
  241.  
  242. //////////////////////////////////////////////////////////////////////////////////////
  243. // this is the workhorse routine. It does the continual screen work to make
  244. // this screen saver what it is.
  245. OSErr 
  246. DoDrawFrame(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params) 
  247. {
  248.     infostructPtr    info;
  249.     Rect             tmpRect;
  250.     short             a, b;
  251.     RGBColor        changecolor;
  252.  
  253.  
  254.     HLock(storage);
  255.     info = (infostructPtr)(*storage);
  256.  
  257. #ifdef DEBUGIT
  258. SetRect( &tmpRect, 0, 0, 50, 20);
  259. EraseRect( &tmpRect);
  260. MoveTo( 10, 15);
  261. a = info->xvel;
  262. b = info->yvel;
  263. if (a < 0) {
  264.     DrawChar('-');
  265.     DrawChar('0' - a);
  266. } else {
  267.     DrawChar( '+');
  268.     DrawChar( '0' + a);
  269. }
  270. DrawChar('.');
  271. if (b < 0) {
  272.     DrawChar('-');
  273.     DrawChar('0' - (b/10) );
  274.     DrawChar('0' - (b%10) );
  275. } else {
  276.     DrawChar('+');
  277.     DrawChar('0' + (b/10) );
  278.     DrawChar('0' + (b%10) );
  279. }
  280.  
  281. #endif
  282.  
  283. // -------------------------------------------------------------------------
  284. //            ALL DONE ... or major reset coming ... boom
  285. // -------------------------------------------------------------------------
  286.         if (info->state == RAE_RESET) {
  287.             short i;
  288.             
  289.             // aaggghhh!!!
  290.             if (info->sndScream != (Handle)NULL ) {
  291.                 long    waste;
  292.                 
  293.                 PlaySound( info->soundInfo, params->sndChannel, info->sndScream);
  294.                 Delay(30L, &waste);
  295.             }
  296.             
  297.             
  298.             // set up the GND 
  299.             for (i=0; i<128; i++) {
  300.                 info->x = i<<3;
  301.                 if (info->x <= XMIN+8 || info->x >= XMAX-8)
  302.                     info->GND[i] = 0;
  303.                 else {
  304.                     info->GND[i] = BOT - 9;
  305.                     if (i&01)
  306.                         if (info->GND[i-1]==0)
  307.                             info->GND[i] = 0;
  308.                         else
  309.                             info->GND[i] -= 7;
  310.                 }
  311.             }
  312.     
  313.             // darken the screen ...
  314.             FillRgn(blankRgn, params->qdGlobalsCopy->qdBlack);
  315.             info->state = RAE_STARTING;
  316.             info->failedToStart = 0;
  317.             HUnlock(storage);
  318.             return noErr;
  319.         }
  320.     
  321.     
  322. // -------------------------------------------------------------------------
  323. //            BALL DONE  start another now
  324. // -------------------------------------------------------------------------
  325.         if (info->state == RAE_DONE) {
  326.  
  327.             info->state = RAE_STARTING;
  328.             info->failedToStart = 0;
  329.             HUnlock(storage);
  330.             return noErr;
  331.         }
  332.     
  333. // -------------------------------------------------------------------------
  334. //            STARTING OUT
  335. // -------------------------------------------------------------------------
  336.     if (info->state == RAE_STARTING) {    
  337.  
  338.         if (info->failedToStart > MAX_ITERATIONS) {
  339.             info->state = RAE_RESET;
  340.             HUnlock(storage);
  341.             return noErr;
  342.         }
  343.  
  344.             info->xpos = Random() & 0177; // 0177 == 127 == 0x7F
  345.             if (info->GND[info->xpos] <= TOP) {
  346.                 info->failedToStart++;
  347.                 HUnlock(storage);
  348.                 return noErr;
  349.             }
  350.             info->failedToStart = 0;
  351.  
  352.             info->x = (info->xpos) << 3;
  353.             //  |01 means an odd number
  354.             //    &07 means to ensure only the last 3 bits are on
  355.             // info->xvel = 4 - ((Random()|01) & 07);
  356.             info->xvel = 4 - 
  357.                 ( (RangedRdm(0, 255) | 01) & 07 );
  358.                 
  359.             info->yacc = 1;
  360.             info->yvel = 1;        // was 0
  361.             info->y = TOP;
  362.             info->state = RAE_FALLING;
  363.  
  364.             info->curFace = info->lastFace =  0;
  365.  
  366.             info->xx = info->yy = 0;        // joe
  367.  
  368.             drawit(params, info, info->x, info->y);            
  369.  
  370.             HUnlock(storage);
  371.             return noErr;
  372.     }
  373.     
  374. // -------------------------------------------------------------------------
  375. //             FALLING 
  376. // -------------------------------------------------------------------------
  377.     if (info->state == RAE_FALLING) {
  378.         long        waste;
  379.         short        eraseX, eraseY;            // saved values of where to erase
  380.         
  381.     
  382.         // we'll get called into this section with the info->time var incremented
  383.         // through each iteration ...
  384.         info->time++;
  385.         
  386.         
  387.         // save the values - so we erase closer to the time
  388.         // when we draw (reduce that flicker)
  389.         eraseX = info->x;
  390.         eraseY = info->y;
  391.         
  392.         // save the x and the y 
  393.         info->xx = info->x; 
  394.         info->yy = info->y; 
  395.         
  396.         // update the acceleration
  397.         info->yvel += info->yacc;
  398.  
  399.         // move it along it's way
  400.         info->y += info->yvel;
  401.         info->x += info->xvel;
  402.         
  403.         if (info->y > info->GND[info->x>>3]) {    /* bounce? */
  404.  
  405.             // make a noise
  406.             if (info->sndBounce != (Handle)NULL  
  407. #ifdef SOUND_TIMER
  408.                     && ( TickCount() > (info->soundTicks + params->controlValues[2] ))
  409. #else
  410.                     && !SoundBusy( info->soundInfo, params->sndChannel)
  411. #endif
  412.                      ) {
  413.                 info->soundTicks = TickCount();
  414.                 PlaySound( info->soundInfo, params->sndChannel, info->sndBounce);
  415.             }
  416.  
  417.             
  418. #ifdef DOUBLE_FACE
  419.             // if we're going fast, show an extra face, at the bounce
  420.             if (info->yvel>5) {
  421.                 short savedFace;
  422.                 savedFace = info->lastFace;
  423.                 
  424.                 if (info->numFaces > 1)  info->curFace = 1;
  425.                 drawit(params, info, info->x, info->y);        // place the face
  426.                 Delay(1L, &waste);
  427.                 drawit(params, info, info->x, info->y);        // erase the face
  428.                 info->lastFace = savedFace;
  429.                 
  430.             } else 
  431. #endif // DOUBLE_FACE
  432.                 if (info->numFaces > 1) info->curFace = 1;
  433.                 
  434.             if (info->y <= info->GND[info->xx>>3]) { /* side collision? */
  435.                 info->x = info->xx;
  436.                 info->xvel = -info->xvel;
  437.  
  438.             } else if (info->yy <= info->GND[info->x>>3]) { /*bottom? */
  439.  
  440.                 info->y = info->yy;
  441.                 info->yvel = -info->yvel;
  442.                 
  443.             } else {    /* corner */
  444.             
  445.                 info->x = info->xx;
  446.                 info->y = info->yy;
  447.                 
  448.                 info->xvel = -info->xvel;
  449.                 info->yvel = -info->yvel;
  450. #if 0        
  451.                 if (info->xvel == 0)        // joehack
  452.                     info->xvel = -2;
  453.                 if (info->yvel > 0)            // joehack
  454.                     info->yvel -= info->yacc;
  455. #endif                
  456.             }
  457.             
  458.             // every 15 bounces (?) (\017) we decay the x velocity
  459.             if ((info->time & 017) == 0)
  460.                 info->xvel = decay(info->xvel);
  461.             
  462.             // is it down to zero ?
  463.             if (info->xvel == 0) {
  464.             
  465.                 info->xpos = (info->x) >> 3;
  466.  
  467.                     // go right 
  468.                 if (info->GND[info->xpos-1] < info->GND[info->xpos]
  469.                  && info->GND[info->xpos]   < info->GND[info->xpos+1])
  470.                     info->xvel = 1;
  471.                     /* go left */
  472.                 else if (info->GND[info->xpos-1] > info->GND[info->xpos]
  473.                       && info->GND[info->xpos]   > info->GND[info->xpos+1])
  474.                     info->xvel = -1;
  475.                     /* on hilltop */
  476.                 else if (info->GND[info->xpos-1] > info->GND[info->xpos]
  477.                       && info->GND[info->xpos]   < info->GND[info->xpos+1]) {
  478.                     if (Random() & 01)
  479.                         info->xvel = 1;
  480.                     else
  481.                         info->xvel = -1;
  482.                 }
  483.             }
  484.             
  485.             // decay the y velocity at each bounce
  486.             info->yvel = decay(info->yvel);    
  487.                         
  488.         } // end of 'if BOUNCE' 
  489.             else info->curFace = 0;
  490.  
  491.  
  492.  
  493.         if (params->controlValues[0]){
  494.                 short saveIt;
  495.                 
  496.                 saveIt = info->curFace;
  497.                 
  498.                 info->curFace = info->lastFace;
  499.                 drawit( params, info, eraseX, eraseY);
  500.                 
  501.                 info->curFace = saveIt;
  502.         }
  503.  
  504.         // place the face (was ->xx, ->yy)
  505.         drawit(params, info, info->x, info->y);
  506.     
  507.         
  508.         if (info->xvel==0 && info->yvel==0 && info->y > info->GND[info->x>>3]-4) {
  509.             info->state = RAE_SETTLING;
  510.             HUnlock(storage);
  511.             return noErr;
  512.         }
  513.     } // end of the falling section
  514.  
  515.     
  516.     
  517.     
  518. // -------------------------------------------------------------------------
  519. //             SETTLING 
  520. // -------------------------------------------------------------------------
  521.     if (info->state == RAE_SETTLING) {
  522.     
  523.  
  524.         // time to erase it
  525.         drawit(params, info, info->x, info->y);    
  526.  
  527.         info->curFace = 0;
  528.  
  529.         /* find stable position */
  530.         if (info->GND[(info->xpos)-1] <    info->GND[info->xpos] && 
  531.             info->GND[info->xpos]   >    info->GND[(info->xpos)+1]) {
  532.             
  533.             // place it?
  534.             drawit(params, info, (info->xpos)<<3, info->GND[info->xpos]);
  535.             // update the "ground" array to know there is something here
  536.             info->GND[info->xpos] -= 21;
  537.             
  538.             if (info->GND[(info->xpos)-1] <= 0)
  539.                 info->GND[info->xpos] -= 7;
  540.                 
  541.             info->GND[(info->xpos)+1] -= 7;
  542.             info->state = RAE_DONE;    // all done
  543.             HUnlock(storage);
  544.             return noErr;
  545.         }
  546.         
  547.         /* roll right */
  548.         if (    info->GND[(info->xpos)-1]    <    info->GND[info->xpos] && 
  549.                 info->GND[info->xpos]        <    info->GND[(info->xpos)+1]) {
  550.             info->xpos++;
  551.             HUnlock(storage);
  552.             return noErr;
  553.         }
  554.         /* roll left */
  555.         if (    info->GND[(info->xpos)-1]    >    info->GND[info->xpos] && 
  556.                 info->GND[info->xpos]        >    info->GND[(info->xpos)+1]) {
  557.             info->xpos--;
  558.             HUnlock(storage);
  559.             return noErr;
  560.         }
  561.         /* on hilltop, choose at Random */
  562.         if (    info->GND[(info->xpos)-1]    >    info->GND[info->xpos] && 
  563.                 info->GND[info->xpos]        <    info->GND[(info->xpos)+1]) {
  564.             if (Random() & 01)
  565.                 info->xpos++;
  566.             else
  567.                 info->xpos--;
  568.             HUnlock(storage);
  569.             return noErr;
  570.         }
  571.         
  572.         // none of the above tests worked ... so something is wrong!!!!!
  573.         /* else botch */
  574.         if (info->sndScream != (Handle)NULL ) {
  575.             long waste;
  576.             
  577.             info->soundTicks = TickCount();
  578.             PlaySound( info->soundInfo, params->sndChannel, info->sndScream);
  579.             Delay(30L, &waste);
  580.         }
  581.  
  582.         // place the face
  583.         // drawit(params, info, (info->xpos)<<3, info->GND[info->xpos]);
  584.         
  585.         // erase the screen
  586.         //PaintRect(&(info->myRect) );
  587.         info->state = RAE_RESET;    // was RAE_DONE all done
  588.         
  589.         HUnlock(storage);
  590.         return noErr;
  591.     }    
  592.  
  593.  
  594. AllDone:
  595.     HUnlock(storage);
  596.     return noErr;
  597. }
  598.  
  599. //////////////////////////////////////////////////////////////////////////////////////
  600. // this is called when they click on something in the control panel
  601. OSErr 
  602. DoSetUp(RgnHandle blankRgn, short message, GMParamBlockPtr params) {
  603.  
  604.     return noErr;
  605. }
  606.  
  607.  
  608.  
  609. OSErr DoSelected(RgnHandle blankRgn, short message, GMParamBlockPtr params) {
  610.     return noErr;
  611. }
  612.  
  613.  
  614.  
  615. OSErr DoAboutBox(RgnHandle blankRgn, short message, GMParamBlockPtr params) {
  616.  
  617.     return noErr;
  618. }
  619.  
  620.  
  621.  
  622. // drawit - place the rae on the screen 
  623. // pass the params + the locked down pointer to the infostruct
  624. drawit(params, info, x, y)
  625. GMParamBlockPtr params;
  626. infostructPtr info;
  627. int x,y;
  628. {       
  629.     int i;
  630.     Rect trect;
  631.     RGBColor        black = {0,0,0}, White = {65535,65535,65535};
  632. volatile    register Boolean *synchFlag;
  633.     long    waste;
  634.  
  635.  
  636.     if (x<XMIN)
  637.         x = XMIN+8;
  638.         
  639.     if (y<TOP)
  640.         y = TOP+8;
  641.         
  642.     if (x>XMAX)
  643.         x = XMAX-8;
  644.     
  645.     info->xpos = x>>3;
  646.     if (y > info->GND[info->xpos])
  647.         y = info->GND[info->xpos];
  648.  
  649.     /* was a call to bitblt() */
  650.     SetRect(&trect, x-12, y-8, x+4, y+8);
  651.  
  652.     if ( params->colorQDAvail ) {
  653.         RGBForeColor (&black);            // added to ensure niceness :)
  654.         RGBBackColor (&White);
  655.     }    
  656.  
  657.     
  658.     info->face.baseAddr = *info->faceSICN + (info->curFace * sizeof( sicnStruct ) );
  659.     info->lastFace = info->curFace;
  660.     HLock( info->faceSICN );
  661.  
  662.     SynchVBL( 0 );
  663.     
  664.     CopyBits(&info->face, ¶ms->qdGlobalsCopy->qdThePort->portBits, 
  665.             &info->face.bounds, &trect, 
  666.                 srcXor, 0L);
  667.     //Delay(1, &waste);
  668.     
  669.     HUnlock( info->faceSICN);
  670.  
  671. }
  672.  
  673. decay(v)
  674. register v;
  675. {
  676.     if (v==0)
  677.         return(v);
  678.     if (v > 0)
  679.         return(v-1-(v>>3));
  680.     return(v+1-(v>>3));
  681. }
  682.  
  683.  
  684.  
  685. // this is from the Think C reference code example ...
  686. unsigned short RangedRdm( unsigned short min, unsigned short max )
  687. /* assume that min is less than max */
  688. {
  689.     // uh ... not this isn't quite right - it's between 0 and 65535, not 65536
  690.     unsigned    qdRdm;    /* treat return value as 0-65536 */
  691.     long    range, t;
  692.     
  693.     // just to be safe, I'll put this here
  694.     if (min > max) {
  695.         DebugStr("\pMin greater then Max in RangedRdm. Type 'G' and return to continue.");
  696.         return min;
  697.     }
  698.     
  699.     qdRdm = Random();
  700.     range = max - min;
  701.     // max - min gives us the the difference between max and min ... that is 
  702.     // not inclusive. It gives us { min <= range < max }
  703.     // so we never see that max number!!
  704.     range++;
  705.     t = ((long)qdRdm * range) / 65536;     /* now 0 <= t <= range */
  706.     return( t+min );
  707. }
  708.